Visualize feature counts and variability

log10 = 0 is equale to a variance of 1 log10 = -2 is 0.01 log10 = -4
is 0.0001
ft <- gene_vars[gene_vars > 0]
quant <- quantile(gene_vars, 0.95)
hist(ft[ft < quant], breaks = 100, col = "steelblue",
main = "Gene Variance (95% trimmed)", xlab = "Variance")

quant <- quantile(gene_vars, 0.90)
hist(ft[ft < quant], breaks = 100, col = "steelblue",
main = "Gene Variance (90% trimmed)", xlab = "Variance")

quant <- quantile(gene_vars, 0.75)
hist(ft[ft < quant], breaks = 100, col = "steelblue",
main = "Gene Variance (75% trimmed)", xlab = "Variance")

NA
NA
NA
NA
NA


ggplot(df, aes(x = mean, y = variance)) +
geom_point(alpha = 0.3, color = "steelblue") +
scale_x_log10() +
scale_y_log10() +
labs(title = "Gene Dispersion", x = "Mean Expression", y = "Variance") +
theme_minimal()
ggplot(df, aes(x = mean, y = variance)) +
geom_point(alpha = 0.3, color = "steelblue") +
labs(title = "Gene Dispersion", x = "Mean Expression", y = "Variance") +
theme_minimal()
ggplot(df, aes(x = mean, y = variance)) +
geom_point(alpha = 0.3, color = "steelblue") +
scale_y_log10() +
labs(title = "Gene Dispersion", x = "Mean Expression", y = "Variance") +
theme_minimal()

ggplot(df_ft, aes(x = mean, y = variance)) +
geom_point(alpha = 0.3, color = "steelblue") +
scale_x_log10() +
scale_y_log10() +
labs(title = "Gene Dispersion", x = "Mean Expression", y = "Variance") +
theme_minimal()

ggplot(df_ft, aes(x = mean, y = variance)) +
geom_point(alpha = 0.3, color = "steelblue") +
labs(title = "Gene Dispersion", x = "Mean Expression", y = "Variance") +
theme_minimal()

ggplot(df_ft, aes(x = mean, y = variance)) +
geom_point(alpha = 0.3, color = "steelblue") +
scale_y_log10() +
labs(title = "Gene Dispersion", x = "Mean Expression", y = "Variance") +
theme_minimal()

NA
NA

# cumulative variance plot
sorted_vars <- sort(gene_vars, decreasing = TRUE)
cumvar <- cumsum(sorted_vars) / sum(sorted_vars)
plot(cumvar, type = "l", lwd = 2, col = "darkgreen",
xlab = "Top N Genes", ylab = "Cumulative Variance Explained",
main = "Cumulative Variance Plot")

How “vst” variance colculaton works

Mean variance plot method


ggplot(df_ft, aes(x = mean, y = dispersion)) +
geom_point(alpha = 0.3, color = "steelblue") +
scale_x_log10() +
scale_y_log10() +
labs(x = "Log10 Mean Expression", y = "Log10 Dispersion") +
theme_minimal()
# Set your MVP thresholds
mean_cutoff <- c(0.1, 8)
dispersion_cutoff <- c(1, 50000) # Inf will not be plotted as a line
# Make the plot
ggplot(df_ft, aes(x = mean, y = dispersion)) +
geom_point(alpha = 0.3, color = "steelblue") +
scale_x_log10() +
scale_y_log10() +
# Add vertical lines for mean cutoff
geom_vline(xintercept = log10(mean_cutoff[1]), linetype = "dashed", color = "darkred") +
geom_vline(xintercept = log10(mean_cutoff[2]), linetype = "dashed", color = "darkred") +
# Add horizontal lines for dispersion cutoff (excluding Inf)
geom_hline(yintercept = log10(dispersion_cutoff[1]), linetype = "dashed", color = "darkgreen") +
labs(x = "Log10 Mean Expression", y = "Log10 Dispersion") +
theme_minimal()
ggplot(df_ft, aes(x = mean, y = dispersion)) +
geom_point(alpha = 0.3, color = "steelblue") +
# Add vertical lines for mean cutoff
geom_vline(xintercept = mean_cutoff[1], linetype = "dashed", color = "darkred") +
geom_vline(xintercept = mean_cutoff[2], linetype = "dashed", color = "darkred") +
# Add horizontal lines for dispersion cutoff (excluding Inf)
geom_hline(yintercept = dispersion_cutoff[1], linetype = "dashed", color = "darkgreen") +
labs(x = "Mean Expression", y = "Dispersion") +
theme_minimal()

NA
NA
Plot dispersion

Explore Variable Feature Selection Overlap
seu <- FindVariableFeatures(seu, selection.method = "dispersion",
loess.span = 0.3,
clip.max = "auto",
num.bin = 20,
nfeatures = 2000,
binning.method = "equal_width",
mean.cutoff = c(0.1, 8),
dispersion.cutoff = c(1, Inf),
verbose = TRUE)
G3;Finding variable features for layer data
gCalculating gene means
0% 10 20 30 40 50 60 70 80 90 100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variance to mean ratios
0% 10 20 30 40 50 60 70 80 90 100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Var_ft_dis <- VariableFeatures(seu)
seu@misc$Var_ft_dis <- Var_ft_dis
VariableFeatures(seu) <- seu@misc$Var_ft_dis
# Identify the 10 most highly variable genes
top10dis <- head(VariableFeatures(seu), 10)
# plot variable features with and without labels
plot3 <- VariableFeaturePlot(seu, assay = "RNA", selection.method = "dispersion",top10dis, repel = TRUE)
G1;H1;Errorh in VariableFeaturePlot(seu, assay = "RNA", selection.method = "dispersion", :
unused argument (repel = TRUE)
Error during wrapup: not that many frames on the stack
Error: no more error handlers available (recursive errors?); invoking 'abort' restart
g
LabelPoints(plot = plot2, points = top10dis, repel = TRUE)
G3;When using repel, set xnudge and ynudge to 0 for optimal results
gG2;H2;Warningh: Removed 2 rows containing missing values or values outside the scale range (`geom_point()`).g

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKQm9udXMgdmlzdWFsaXphdGlvbiBvciBjb21wYXJpc29ucwoKYGBge3J9CnJtKGxpc3QgPSBscygpKQoKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoTWF0cml4KQpsaWJyYXJ5KFVwU2V0UikKCiMgeW91ciBkYXRhIG9yIGFueSBleGFtcGxlIGRhdGEgY2FuIGJlIHVzZWQKCiMgc2V1IDwtIHJlYWRSRFMoIlNldXJhdE9iamVjdC5yZHMiKQpzZXUKCmBgYAoKCgoKCgojIFZpc3VhbGl6ZSBmZWF0dXJlIGNvdW50cyBhbmQgdmFyaWFiaWxpdHkKYGBge3J9CgojIENvbXB1dGUgdmFyaWFuY2Ugb2YgYWxsIGdlbmVzIG1hbnVhbGx5IChpZiBub3QgdXNpbmcgU2V1cmF0J3MgdmFyaWFibGUgZmVhdHVyZXMpCgpleHByX21hdCA8LSBHZXRBc3NheURhdGEoc2V1LCBhc3NheSA9ICJSTkEiLCBsYXllciA9ICJjb3VudHMiKQpleHByX21hdFsxOjgsMTo1XQojIFN0ZXAgMTogR2V0IG1lYW5zCmdlbmVfbWVhbnMgPC0gcm93TWVhbnMoZXhwcl9tYXQpCgojIFN0ZXAgMjogQ29tcHV0ZSBzcXVhcmVkIGRldmlhdGlvbnMgYW5kIG1lYW4KZ2VuZV92YXJzIDwtIGFzLm51bWVyaWMocm93TWVhbnMoZXhwcl9tYXReMikgLSBnZW5lX21lYW5zXjIpCm5hbWVzKGdlbmVfdmFycykgPC0gcm93bmFtZXMoZXhwcl9tYXQpCmdlbmVfdmFyc1sxOjEwXQoKZGYgPC0gZGF0YS5mcmFtZShnZW5lID0gbmFtZXMoZ2VuZV92YXJzKSwgdmFyaWFuY2UgPSBnZW5lX3ZhcnMpCgojIEhpc3RvZ3JhbQpoaXN0KGRmJHZhcmlhbmNlLCBicmVha3MgPSAxMDAsIGNvbCA9ICJzdGVlbGJsdWUiLAogICAgIG1haW4gPSAiRGlzdHJpYnV0aW9uIG9mIEdlbmUgVmFyaWFuY2UiLAogICAgIHhsYWIgPSAiVmFyaWFuY2UiKQoKc3VtbWFyeShnZW5lX3ZhcnMpCgoKCmhpc3QobG9nMTAoZ2VuZV92YXJzW2dlbmVfdmFycyA+IDBdKSwgYnJlYWtzID0gMTAwLCBjb2wgPSAidG9tYXRvIiwKICAgICBtYWluID0gIkxvZzEwIEdlbmUgVmFyaWFuY2UiLCB4bGFiID0gImxvZzEwKFZhcmlhbmNlKSIpCgoKIyB3aXRoIHBzZXVkbyBjb3VudHMKbG9nX2dlbmVfdmFycyA8LSBsb2cxMChnZW5lX3ZhcnMgKyAxZS02KQpoaXN0KGxvZ19nZW5lX3ZhcnMsIGJyZWFrcyA9IDEwMCwgY29sID0gImRhcmtyZWQiLAogICAgIG1haW4gPSAiTG9nMTAgR2VuZSBWYXJpYW5jZSIsIHhsYWIgPSAibG9nMTAoVmFyaWFuY2UpIikKCgoKYGBgCmxvZzEwID0gMCBpcyBlcXVhbGUgdG8gYSB2YXJpYW5jZSBvZiAxCmxvZzEwID0gLTIgaXMgMC4wMQpsb2cxMCA9IC00IGlzIDAuMDAwMQoKCgoKYGBge3J9CgoKZnQgPC0gZ2VuZV92YXJzW2dlbmVfdmFycyA+IDBdCnF1YW50IDwtIHF1YW50aWxlKGdlbmVfdmFycywgMC45NSkKaGlzdChmdFtmdCA8IHF1YW50XSwgYnJlYWtzID0gMTAwLCBjb2wgPSAic3RlZWxibHVlIiwKICAgICBtYWluID0gIkdlbmUgVmFyaWFuY2UgKDk1JSB0cmltbWVkKSIsIHhsYWIgPSAiVmFyaWFuY2UiKQoKcXVhbnQgPC0gcXVhbnRpbGUoZ2VuZV92YXJzLCAwLjkwKQpoaXN0KGZ0W2Z0IDwgcXVhbnRdLCBicmVha3MgPSAxMDAsIGNvbCA9ICJzdGVlbGJsdWUiLAogICAgIG1haW4gPSAiR2VuZSBWYXJpYW5jZSAoOTAlIHRyaW1tZWQpIiwgeGxhYiA9ICJWYXJpYW5jZSIpCgoKcXVhbnQgPC0gcXVhbnRpbGUoZ2VuZV92YXJzLCAwLjc1KQpoaXN0KGZ0W2Z0IDwgcXVhbnRdLCBicmVha3MgPSAxMDAsIGNvbCA9ICJzdGVlbGJsdWUiLAogICAgIG1haW4gPSAiR2VuZSBWYXJpYW5jZSAoNzUlIHRyaW1tZWQpIiwgeGxhYiA9ICJWYXJpYW5jZSIpCgoKCgoKYGBgCgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpwbHVzX2dlbmVfdmFycyA9IGdlbmVfdmFycyArIDAuMDAwMDAwMDAwMQoKCmRmIDwtIGRhdGEuZnJhbWUoCiAgZ2VuZSA9IHJvd25hbWVzKGV4cHJfbWF0KSwKICBtZWFuID0gZ2VuZV9tZWFucywKICB2YXJpYW5jZSA9IHBsdXNfZ2VuZV92YXJzCikKCmRmX2Z0IDwtIGRmW2RmJHZhcmlhbmNlID4gMC4wMDAwMSAsXQoKZ2dwbG90KGRmLCBhZXMoeCA9IG1lYW4sIHkgPSB2YXJpYW5jZSkpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC4zLCBjb2xvciA9ICJzdGVlbGJsdWUiKSArCiAgc2NhbGVfeF9sb2cxMCgpICsKICBzY2FsZV95X2xvZzEwKCkgKwogIGxhYnModGl0bGUgPSAiR2VuZSBEaXNwZXJzaW9uIiwgeCA9ICJNZWFuIEV4cHJlc3Npb24iLCB5ID0gIlZhcmlhbmNlIikgKwogIHRoZW1lX21pbmltYWwoKQoKCmdncGxvdChkZiwgYWVzKHggPSBtZWFuLCB5ID0gdmFyaWFuY2UpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMywgY29sb3IgPSAic3RlZWxibHVlIikgKwogIGxhYnModGl0bGUgPSAiR2VuZSBEaXNwZXJzaW9uIiwgeCA9ICJNZWFuIEV4cHJlc3Npb24iLCB5ID0gIlZhcmlhbmNlIikgKwogIHRoZW1lX21pbmltYWwoKQoKCmdncGxvdChkZiwgYWVzKHggPSBtZWFuLCB5ID0gdmFyaWFuY2UpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMywgY29sb3IgPSAic3RlZWxibHVlIikgKwogIHNjYWxlX3lfbG9nMTAoKSArCiAgbGFicyh0aXRsZSA9ICJHZW5lIERpc3BlcnNpb24iLCB4ID0gIk1lYW4gRXhwcmVzc2lvbiIsIHkgPSAiVmFyaWFuY2UiKSArCiAgdGhlbWVfbWluaW1hbCgpCgoKCmdncGxvdChkZl9mdCwgYWVzKHggPSBtZWFuLCB5ID0gdmFyaWFuY2UpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMywgY29sb3IgPSAic3RlZWxibHVlIikgKwogIHNjYWxlX3hfbG9nMTAoKSArCiAgc2NhbGVfeV9sb2cxMCgpICsKICBsYWJzKHRpdGxlID0gIkdlbmUgRGlzcGVyc2lvbiIsIHggPSAiTWVhbiBFeHByZXNzaW9uIiwgeSA9ICJWYXJpYW5jZSIpICsKICB0aGVtZV9taW5pbWFsKCkKCgpnZ3Bsb3QoZGZfZnQsIGFlcyh4ID0gbWVhbiwgeSA9IHZhcmlhbmNlKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjMsIGNvbG9yID0gInN0ZWVsYmx1ZSIpICsKICBsYWJzKHRpdGxlID0gIkdlbmUgRGlzcGVyc2lvbiIsIHggPSAiTWVhbiBFeHByZXNzaW9uIiwgeSA9ICJWYXJpYW5jZSIpICsKICB0aGVtZV9taW5pbWFsKCkKCgpnZ3Bsb3QoZGZfZnQsIGFlcyh4ID0gbWVhbiwgeSA9IHZhcmlhbmNlKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjMsIGNvbG9yID0gInN0ZWVsYmx1ZSIpICsKICBzY2FsZV95X2xvZzEwKCkgKwogIGxhYnModGl0bGUgPSAiR2VuZSBEaXNwZXJzaW9uIiwgeCA9ICJNZWFuIEV4cHJlc3Npb24iLCB5ID0gIlZhcmlhbmNlIikgKwogIHRoZW1lX21pbmltYWwoKQoKCgoKYGBgCgoKCgoKCgpgYGB7cn0KIyBsYXJnZXIgdmFyaWFuY2UgCgpxdWFudCA8LSBxdWFudGlsZShnZW5lX3ZhcnMsIDAuNzUpCmxhcmdlX3ZhciA8LSBnZW5lX3ZhcnNbZ2VuZV92YXJzID4gcXVhbnRdCnN1bW1hcnkobGFyZ2VfdmFyKQoKaGlzdChsYXJnZV92YXJbbGFyZ2VfdmFyIDwgM10sIGJyZWFrcyA9IDEwMCwgY29sID0gInN0ZWVsYmx1ZSIsCiAgICAgbWFpbiA9ICJHZW5lIFZhcmlhbmNlIGFib3ZlIDc1JSBwZXJjZW50aWxlIGFuZCBsb3dlciB0aGFuIDMiLCB4bGFiID0gIlZhcmlhbmNlIikKCgoKcXVhbnQgPC0gcXVhbnRpbGUoZ2VuZV92YXJzLCAwLjk1KQpsYXJnZV92YXIgPC0gZ2VuZV92YXJzW2dlbmVfdmFycyA+IHF1YW50XQpzdW1tYXJ5KGxhcmdlX3ZhcikKaGlzdChsYXJnZV92YXJbbGFyZ2VfdmFyIDwgMjAwXSwgYnJlYWtzID0gMTAwLCBjb2wgPSAic3RlZWxibHVlIiwKICAgICBtYWluID0gIkdlbmUgVmFyaWFuY2UgYWJvdmUgOTUlIHBlcmNlbnRpbGUgYW5kIGxvd2VyIHRoYW4gMjAwIiwgeGxhYiA9ICJWYXJpYW5jZSIpCgoKCnF1YW50IDwtIHF1YW50aWxlKGdlbmVfdmFycywgMC45OSkKbGFyZ2VfdmFyIDwtIGdlbmVfdmFyc1tnZW5lX3ZhcnMgPiBxdWFudF0Kc3VtbWFyeShsYXJnZV92YXIpCmhpc3QobGFyZ2VfdmFyW2xhcmdlX3ZhciA8IDMwMDBdLCBicmVha3MgPSAxMDAsIGNvbCA9ICJzdGVlbGJsdWUiLAogICAgIG1haW4gPSAiR2VuZSBWYXJpYW5jZSBhYm92ZSA5OSUgcGVyY2VudGlsZSAiLCB4bGFiID0gIlZhcmlhbmNlIikKCgoKYGBgCgoKCgoKCgpgYGB7cn0KIyBjdW11bGF0aXZlIHZhcmlhbmNlIHBsb3QKc29ydGVkX3ZhcnMgPC0gc29ydChnZW5lX3ZhcnMsIGRlY3JlYXNpbmcgPSBUUlVFKQpjdW12YXIgPC0gY3Vtc3VtKHNvcnRlZF92YXJzKSAvIHN1bShzb3J0ZWRfdmFycykKCnBsb3QoY3VtdmFyLCB0eXBlID0gImwiLCBsd2QgPSAyLCBjb2wgPSAiZGFya2dyZWVuIiwKICAgICB4bGFiID0gIlRvcCBOIEdlbmVzIiwgeWxhYiA9ICJDdW11bGF0aXZlIFZhcmlhbmNlIEV4cGxhaW5lZCIsCiAgICAgbWFpbiA9ICJDdW11bGF0aXZlIFZhcmlhbmNlIFBsb3QiKQpgYGAKCkhvdyAidnN0IiB2YXJpYW5jZSBjb2xjdWxhdG9uIHdvcmtzCgpgYGB7cn0KIyBleHByX21hdCB3YXMgdGFrZW4gYWJvdmUKbWVhbnMgPC0gcm93TWVhbnMoZXhwcl9tYXQpCnZhcnMgPC0gYXMubnVtZXJpYyhyb3dNZWFucyhleHByX21hdF4yKSAtIGdlbmVfbWVhbnNeMikKCgojIFN0ZXAgMjogTG9nIHRyYW5zZm9ybQpsb2dfbWVhbnMgPC0gbG9nMTAobWVhbnMpICAjIApsb2dfdmFycyA8LSBsb2cxMCh2YXJzKQoKIyBTdGVwIDM6IEZpdCBsb2VzcyBjdXJ2ZQpmaXQgPC0gbG9lc3MobG9nX3ZhcnMgfiBsb2dfbWVhbnMpCgojIFN0ZXAgNDogUHJlZGljdCBleHBlY3RlZCB2YXJpYW5jZQpleHBlY3RlZF9sb2dfdmFycyA8LSBwcmVkaWN0KGZpdCkKCiMgU3RlcCA1OiBQbG90CnBsb3QobG9nX21lYW5zLCBsb2dfdmFycywgcGNoID0gMTYsIGNvbCA9IHJnYigwLjIsIDAuNCwgMC44LCAwLjMpLAogICAgIHhsYWIgPSAibG9nMTAoTWVhbikiLCB5bGFiID0gImxvZzEwKEV4cGVjdGVkIFZhcmlhbmNlKSIsIG1haW4gPSAiTWVhbi1WYXJpYW5jZSB3aXRoIExPRVNTIEZpdCIpCmxpbmVzKGxvZ19tZWFuc1tvcmRlcihsb2dfbWVhbnMpXSwgZXhwZWN0ZWRfbG9nX3ZhcnNbb3JkZXIobG9nX21lYW5zKV0sCiAgICAgIGNvbCA9ICJyZWQiLCBsd2QgPSAyKQoKYGBgCgpNZWFuIHZhcmlhbmNlIHBsb3QgbWV0aG9kCgpgYGB7cn0KCiMgMy4gQ29tcHV0ZSAiZGlzcGVyc2lvbiIgKHZhcmlhbmNlIC8gbWVhbikKZGlzcGVyc2lvbiA8LSAoZ2VuZV92YXJzICsgMC4wMDAwMDAwMSkgLyBnZW5lX21lYW5zCgpkZiA8LSBkYXRhLmZyYW1lKAogIGdlbmUgPSByb3duYW1lcyhleHByX21hdCksCiAgbWVhbiA9IGdlbmVfbWVhbnMsCiAgdmFyaWFuY2UgPSBnZW5lX3ZhcnMsCiAgZGlzcGVyc2lvbiA9IGRpc3BlcnNpb24KKQoKZGZfZnQgPC0gZGZbIWlzLm5hbihkZiRkaXNwZXJzaW9uKSwgXQpkZl9mdCA8LSBkZltpcy5maW5pdGUoZGYkZGlzcGVyc2lvbikgJiAhaXMubmEoZGYkZGlzcGVyc2lvbiksIF0KCgoKZ2dwbG90KGRmX2Z0LCBhZXMoeCA9IG1lYW4sIHkgPSBkaXNwZXJzaW9uKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjMsIGNvbG9yID0gInN0ZWVsYmx1ZSIpICsKICBzY2FsZV94X2xvZzEwKCkgKwogIHNjYWxlX3lfbG9nMTAoKSArCiAgbGFicyh4ID0gIkxvZzEwIE1lYW4gRXhwcmVzc2lvbiIsIHkgPSAiTG9nMTAgRGlzcGVyc2lvbiIpICsKICB0aGVtZV9taW5pbWFsKCkKCgojIFNldCB5b3VyIE1WUCB0aHJlc2hvbGRzCm1lYW5fY3V0b2ZmIDwtIGMoMC4xLCA4KQpkaXNwZXJzaW9uX2N1dG9mZiA8LSBjKDEsIDUwMDAwKSAgIyBJbmYgd2lsbCBub3QgYmUgcGxvdHRlZCBhcyBhIGxpbmUKCiMgTWFrZSB0aGUgcGxvdApnZ3Bsb3QoZGZfZnQsIGFlcyh4ID0gbWVhbiwgeSA9IGRpc3BlcnNpb24pKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMywgY29sb3IgPSAic3RlZWxibHVlIikgKwogIHNjYWxlX3hfbG9nMTAoKSArCiAgc2NhbGVfeV9sb2cxMCgpICsKICAjIEFkZCB2ZXJ0aWNhbCBsaW5lcyBmb3IgbWVhbiBjdXRvZmYKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBsb2cxMChtZWFuX2N1dG9mZlsxXSksIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImRhcmtyZWQiKSArCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBsb2cxMChtZWFuX2N1dG9mZlsyXSksIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImRhcmtyZWQiKSArCiAgIyBBZGQgaG9yaXpvbnRhbCBsaW5lcyBmb3IgZGlzcGVyc2lvbiBjdXRvZmYgKGV4Y2x1ZGluZyBJbmYpCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gbG9nMTAoZGlzcGVyc2lvbl9jdXRvZmZbMV0pLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJkYXJrZ3JlZW4iKSArCiAgbGFicyh4ID0gIkxvZzEwIE1lYW4gRXhwcmVzc2lvbiIsIHkgPSAiTG9nMTAgRGlzcGVyc2lvbiIpICsKICB0aGVtZV9taW5pbWFsKCkKCgoKZ2dwbG90KGRmX2Z0LCBhZXMoeCA9IG1lYW4sIHkgPSBkaXNwZXJzaW9uKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjMsIGNvbG9yID0gInN0ZWVsYmx1ZSIpICsKCiAgIyBBZGQgdmVydGljYWwgbGluZXMgZm9yIG1lYW4gY3V0b2ZmCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWVhbl9jdXRvZmZbMV0sIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImRhcmtyZWQiKSArCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBtZWFuX2N1dG9mZlsyXSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiZGFya3JlZCIpICsKICAjIEFkZCBob3Jpem9udGFsIGxpbmVzIGZvciBkaXNwZXJzaW9uIGN1dG9mZiAoZXhjbHVkaW5nIEluZikKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBkaXNwZXJzaW9uX2N1dG9mZlsxXSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiZGFya2dyZWVuIikgKwogIGxhYnMoeCA9ICJNZWFuIEV4cHJlc3Npb24iLCB5ID0gIkRpc3BlcnNpb24iKSArCiAgdGhlbWVfbWluaW1hbCgpCgoKCgpgYGAKClBsb3QgZGlzcGVyc2lvbiAKCmBgYHtyfQoKIyBCaW4gZ2VuZXMgYnkgbWVhbiBleHByZXNzaW9uCmRmX2JpbiA8LSBkZl9mdCAlPiUKICBtdXRhdGUoYmluID0gbnRpbGUobWVhbiwgMjApKSAlPiUgICMgMjAgYmlucyBsaWtlIFNldXJhdAogIGdyb3VwX2J5KGJpbikgJT4lCiAgbXV0YXRlKHNjYWxlZF9kaXNwZXJzaW9uID0gc2NhbGUoZGlzcGVyc2lvbilbLDFdKSAlPiUKICB1bmdyb3VwKCkKCiMgUGxvdDogbG9nMTAgbWVhbiB2cy4gc2NhbGVkIGRpc3BlcnNpb24KZ2dwbG90KGRmX2JpbiwgYWVzKHggPSBtZWFuLCB5ID0gc2NhbGVkX2Rpc3BlcnNpb24pKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMywgY29sb3IgPSAic3RlZWxibHVlIikgKwogIHNjYWxlX3hfbG9nMTAoKSArCiAgbGFicygKICAgIHggPSAiTG9nMTAgTWVhbiBFeHByZXNzaW9uIiwKICAgIHkgPSAiU2NhbGVkIERpc3BlcnNpb24gKFotc2NvcmUpIiwKICAgIHRpdGxlID0gIkRpc3BlcnNpb24gTWV0aG9kIChTZXVyYXQpIgogICkgKwogIHRoZW1lX21pbmltYWwoKQoKCmBgYAoKCkV4cGxvcmUgVmFyaWFibGUgRmVhdHVyZSBTZWxlY3Rpb24gT3ZlcmxhcAoKYGBge3J9CgoKCiMgY2FsY3VsYXRlIHZhcmlhYmxlIGZlYXR1cmVzIGluIGRpZmZlcmVudCB3YXlzCkZpbmRWYXJpYWJsZUZlYXR1cmVzKHNldSwgc2VsZWN0aW9uLm1ldGhvZCA9ICJ2c3QiLAogIGxvZXNzLnNwYW4gPSAwLjMsCiAgY2xpcC5tYXggPSAiYXV0byIsCiAgbnVtLmJpbiA9IDIwLAogIGJpbm5pbmcubWV0aG9kID0gImVxdWFsX3dpZHRoIiwKICBuZmVhdHVyZXMgPSAyMDAwLCAjIGRlZmF1bHQKICBtZWFuLmN1dG9mZiA9IGMoMC4xLCA4KSwgIyB1c2VkIGluIG12cAogIGRpc3BlcnNpb24uY3V0b2ZmID0gYygxLCBJbmYpLCAjIHVzZWQgaW4gZGlzcHJlc3Npb24KICB2ZXJib3NlID0gVFJVRSkKCgpWYXJfZnRfdnN0IDwtIFZhcmlhYmxlRmVhdHVyZXMoc2V1KQojIHB1dCB0aGUgZmVhdHVyZXMgaW50byBhIHNwb3Qgd2hlcmUgd2UgY2FuIHJlY292ZXIgdGhlbSBsYXRlcgpzZXVAbWlzYyRWYXJfZnRfdnN0IDwtIFZhcl9mdF92c3QKCnRvcDEwdnN0IDwtIGhlYWQoc2V1QG1pc2MkVmFyX2Z0X3ZzdCwgMTApCnBsb3QxIDwtIFZhcmlhYmxlRmVhdHVyZVBsb3Qoc2V1LCBhc3NheSA9ICJSTkEiLCBzZWxlY3Rpb24ubWV0aG9kID0gInZzdCIpIApMYWJlbFBvaW50cyhwbG90ID0gcGxvdDEsIHBvaW50cyA9IHRvcDEwdnN0LCByZXBlbCA9IFRSVUUpCgoKY2F0KCItLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuIikKCnNldSA8LSBGaW5kVmFyaWFibGVGZWF0dXJlcyhzZXUsIHNlbGVjdGlvbi5tZXRob2QgPSAibWVhbi52YXIucGxvdCIsCiAgbG9lc3Muc3BhbiA9IDAuMywKICBjbGlwLm1heCA9ICJhdXRvIiwKICBudW0uYmluID0gMjAsCiAgYmlubmluZy5tZXRob2QgPSAiZXF1YWxfd2lkdGgiLAogIG1lYW4uY3V0b2ZmID0gYygwLjEsIDgpLAogIGRpc3BlcnNpb24uY3V0b2ZmID0gYygxLCBJbmYpLAogIHZlcmJvc2UgPSBUUlVFKQoKVmFyX2Z0X212cCA8LSBWYXJpYWJsZUZlYXR1cmVzKHNldSkKc2V1QG1pc2MkVmFyX2Z0X212cCA8LSBWYXJfZnRfbXZwCgpWYXJpYWJsZUZlYXR1cmVzKHNldSkgPC0gc2V1QG1pc2MkVmFyX2Z0X212cAojIElkZW50aWZ5IHRoZSAxMCBtb3N0IGhpZ2hseSB2YXJpYWJsZSBnZW5lcwp0b3AxMG12cCA8LSBoZWFkKHNldUBtaXNjJFZhcl9mdF9tdnAsIDEwKQoKIyBwbG90IHZhcmlhYmxlIGZlYXR1cmVzIHdpdGggYW5kIHdpdGhvdXQgbGFiZWxzCnBsb3QyIDwtIFZhcmlhYmxlRmVhdHVyZVBsb3Qoc2V1LCBhc3NheSA9ICJSTkEiLCBzZWxlY3Rpb24ubWV0aG9kID0gIm1lYW4udmFyLnBsb3QiKSAgCkxhYmVsUG9pbnRzKHBsb3QgPSBwbG90MiwgcG9pbnRzID0gdG9wMTBtdnAsIHJlcGVsID0gVFJVRSkKCmNhdCgiLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiIpCgoKc2V1IDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKHNldSwgc2VsZWN0aW9uLm1ldGhvZCA9ICJkaXNwZXJzaW9uIiwKICBsb2Vzcy5zcGFuID0gMC4zLAogIGNsaXAubWF4ID0gImF1dG8iLAogIG51bS5iaW4gPSAyMCwgCiAgIG5mZWF0dXJlcyA9IDIwMDAsCiAgYmlubmluZy5tZXRob2QgPSAiZXF1YWxfd2lkdGgiLAogIG1lYW4uY3V0b2ZmID0gYygwLjEsIDgpLAogIGRpc3BlcnNpb24uY3V0b2ZmID0gYygxLCBJbmYpLAogIHZlcmJvc2UgPSBUUlVFKQoKVmFyX2Z0X2RpcyA8LSBWYXJpYWJsZUZlYXR1cmVzKHNldSkKc2V1QG1pc2MkVmFyX2Z0X2RpcyA8LSBWYXJfZnRfZGlzCgoKVmFyaWFibGVGZWF0dXJlcyhzZXUpIDwtIHNldUBtaXNjJFZhcl9mdF9kaXMKIyBJZGVudGlmeSB0aGUgMTAgbW9zdCBoaWdobHkgdmFyaWFibGUgZ2VuZXMKdG9wMTBkaXMgPC0gaGVhZChWYXJpYWJsZUZlYXR1cmVzKHNldSksIDEwKQoKIyBwbG90IHZhcmlhYmxlIGZlYXR1cmVzIHdpdGggYW5kIHdpdGhvdXQgbGFiZWxzCnBsb3QzIDwtIFZhcmlhYmxlRmVhdHVyZVBsb3Qoc2V1LCBhc3NheSA9ICJSTkEiLCBzZWxlY3Rpb24ubWV0aG9kID0gImRpc3BlcnNpb24iLHRvcDEwZGlzLCByZXBlbCA9IFRSVUUpCkxhYmVsUG9pbnRzKHBsb3QgPSBwbG90MiwgcG9pbnRzID0gdG9wMTBkaXMsIHJlcGVsID0gVFJVRSkKCgoKY2F0KCItLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuIikKCgoKCmBgYAoKCgojIG1ha2UgYW4gdXBzZXQgcGxvdCBjb21wYXJpbmcgdGhlIDMgRmluZFZhcmlhYmxlRmVhdHVyZXMgb3B0aW9ucwpgYGB7cn0KCgp1cHNldChmcm9tTGlzdChsaXN0KHZzdCA9IFZhcl9mdF92c3QsIG12cCA9IFZhcl9mdF9tdnAsIGRpc3AgPSBWYXJfZnRfZGlzKSkpCgojIG1vcmUgb3B0aW9ucyBnZW5lIGxpc3RzIGNhbiBiZSBpbmNsdWRlZCBpZiB3YW50ZWQKCmBgYAoKCgpNYWtlIGFuIHVwc2V0IHBsb3QgZm9yIHRoZSB2YXJpYWJsZSBmZWF0dXJlcyBmb3IgZWFjaCBzYW1wbGUgYW5kIHRoZSBtZXJnZWQgb2JqZWN0CgpgYGB7cn0KCiMgZXhhbXBsZQp1cHNldChmcm9tTGlzdChsaXN0KEMxID0gVmFyX0MxLCBDMiA9IFZhcl9DMiwgQzMgPSBWYXJfQzMsIEM0ID0gVmFyX0M0LCBDb21iaW5lZCA9IFZhcl9vYmopKSkKCmBgYAoKCgoKCgoKCgo=